package com.harmony.pilot.knowledge.scanner;

import com.harmony.pilot.knowledge.entity.CodeFile;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 深度代码扫描器
 * 遍历ohcode目录最深20层，扫描所有.h/.cpp/.c/.gn文件
 * 一个文件都不会漏掉！
 */
@Slf4j
@Service
public class DeepCodeScanner {
    
    @Value("${openharmony.code.base-path:../ohcode}")
    private String basePath;
    
    /** 最大遍历深度 */
    private static final int MAX_DEPTH = 20;
    
    /** 支持的文件扩展名 */
    private static final String[] SUPPORTED_EXTENSIONS = {
        ".h", ".hpp", ".hxx", 
        ".cpp", ".cc", ".cxx", ".c",
        ".gn", ".gni"
    };
    
    /** 版权信息正则 */
    private static final Pattern COPYRIGHT_PATTERN = Pattern.compile(
        "(?i)copyright\\s*(?:©|\\(c\\))?\\s*\\d{4}[\\s\\S]{0,200}",
        Pattern.CASE_INSENSITIVE
    );
    
    /** 许可证正则 */
    private static final Pattern LICENSE_PATTERN = Pattern.compile(
        "(?i)license[d]?\\s*under\\s+([\\w\\s]+)|SPDX-License-Identifier:\\s*([\\w\\-\\.]+)",
        Pattern.CASE_INSENSITIVE
    );
    
    /** 作者信息正则 */
    private static final Pattern AUTHOR_PATTERN = Pattern.compile(
        "(?i)@author\\s+([^\\n]+)|Author[s]?:\\s*([^\\n]+)",
        Pattern.CASE_INSENSITIVE
    );
    
    /**
     * 深度扫描整个代码库
     * @return 扫描到的所有代码文件
     */
    public List<CodeFile> scanAll() {
        log.info("开始深度扫描代码库: {}", basePath);
        log.info("最大遍历深度: {}", MAX_DEPTH);
        
        List<CodeFile> files = new ArrayList<>();
        AtomicInteger fileCount = new AtomicInteger(0);
        AtomicInteger dirCount = new AtomicInteger(0);
        
        Path baseDir = Paths.get(basePath);
        if (!Files.exists(baseDir)) {
            log.error("代码库路径不存在: {}", basePath);
            return files;
        }
        
        try {
            Files.walkFileTree(baseDir, java.util.EnumSet.noneOf(FileVisitOption.class), MAX_DEPTH, 
                new SimpleFileVisitor<Path>() {
                    private int currentDepth = 0;
                    
                    @Override
                    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
                        dirCount.incrementAndGet();
                        
                        String dirName = dir.getFileName().toString();
                        
                        // 跳过明确不需要的目录
                        if (shouldSkipDirectory(dirName)) {
                            log.debug("跳过目录: {}", dir);
                            return FileVisitResult.SKIP_SUBTREE;
                        }
                        
                        currentDepth = baseDir.relativize(dir).getNameCount();
                        if (currentDepth <= MAX_DEPTH) {
                            log.debug("进入目录: {} (深度: {})", dir, currentDepth);
                            return FileVisitResult.CONTINUE;
                        } else {
                            log.warn("达到最大深度，跳过: {}", dir);
                            return FileVisitResult.SKIP_SUBTREE;
                        }
                    }
                    
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                        try {
                            if (isSupportedFile(file)) {
                                CodeFile codeFile = scanFile(file, baseDir);
                                if (codeFile != null) {
                                    files.add(codeFile);
                                    fileCount.incrementAndGet();
                                    
                                    if (fileCount.get() % 1000 == 0) {
                                        log.info("已扫描 {} 个文件...", fileCount.get());
                                    }
                                }
                            }
                        } catch (Exception e) {
                            log.error("扫描文件失败: {}, 错误: {}", file, e.getMessage());
                        }
                        return FileVisitResult.CONTINUE;
                    }
                    
                    @Override
                    public FileVisitResult visitFileFailed(Path file, IOException exc) {
                        log.warn("访问文件失败: {}, 错误: {}", file, exc.getMessage());
                        return FileVisitResult.CONTINUE;
                    }
                });
            
            log.info("===========================================");
            log.info("代码库扫描完成！");
            log.info("扫描目录数: {}", dirCount.get());
            log.info("扫描文件数: {}", fileCount.get());
            log.info("===========================================");
            
        } catch (IOException e) {
            log.error("扫描代码库失败", e);
        }
        
        return files;
    }
    
    /**
     * 扫描单个文件
     */
    private CodeFile scanFile(Path file, Path baseDir) {
        try {
            CodeFile codeFile = new CodeFile();
            
            // 基本信息
            codeFile.setFilePath(file.toString());
            codeFile.setFileName(file.getFileName().toString());
            codeFile.setFileType(getFileExtension(file));
            codeFile.setRelativePath(baseDir.relativize(file).toString());
            
            // 计算深度
            int depth = baseDir.relativize(file).getNameCount() - 1;
            codeFile.setDepthLevel(depth);
            
            // 模块信息
            String[] pathParts = codeFile.getRelativePath().split("[/\\\\]");
            if (pathParts.length > 0) {
                codeFile.setModuleName(pathParts[0]);
                if (pathParts.length > 1) {
                    codeFile.setSubModule(pathParts[1]);
                }
            }
            
            // 文件属性
            BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class);
            codeFile.setFileSize(attrs.size());
            codeFile.setLastModified(LocalDateTime.ofInstant(
                Instant.ofEpochMilli(attrs.lastModifiedTime().toMillis()),
                ZoneId.systemDefault()
            ));
            
            // 读取文件内容
            String content = Files.readString(file, StandardCharsets.UTF_8);
            String[] lines = content.split("\\r?\\n");
            codeFile.setLineCount(lines.length);
            
            // 计算MD5
            codeFile.setContentMd5(calculateMD5(content));
            
            // 提取元数据
            extractMetadata(codeFile, content);
            
            // 判断文件类型
            String relativePath = codeFile.getRelativePath().toLowerCase();
            codeFile.setIsTest(relativePath.contains("/test/") || relativePath.contains("/tests/") || 
                               codeFile.getFileName().contains("test"));
            codeFile.setIsMock(relativePath.contains("mock") || codeFile.getFileName().contains("mock"));
            codeFile.setIsFuzzer(relativePath.contains("fuzzer") || relativePath.contains("fuzz"));
            codeFile.setIsHeader(codeFile.getFileType().matches("\\.(h|hpp|hxx)"));
            
            return codeFile;
            
        } catch (Exception e) {
            log.error("扫描文件失败: {}", file, e);
            return null;
        }
    }
    
    /**
     * 提取文件元数据（版权、许可证、作者等）
     */
    private void extractMetadata(CodeFile codeFile, String content) {
        // 只读取文件前5000个字符（通常元数据在文件开头）
        String header = content.length() > 5000 ? content.substring(0, 5000) : content;
        
        // 提取版权信息
        Matcher copyrightMatcher = COPYRIGHT_PATTERN.matcher(header);
        if (copyrightMatcher.find()) {
            codeFile.setCopyright(copyrightMatcher.group().trim());
        }
        
        // 提取许可证
        Matcher licenseMatcher = LICENSE_PATTERN.matcher(header);
        if (licenseMatcher.find()) {
            String license = licenseMatcher.group(1);
            if (license == null) license = licenseMatcher.group(2);
            codeFile.setLicense(license != null ? license.trim() : null);
        }
        
        // 提取作者信息
        Matcher authorMatcher = AUTHOR_PATTERN.matcher(header);
        StringBuilder authors = new StringBuilder();
        while (authorMatcher.find()) {
            String author = authorMatcher.group(1);
            if (author == null) author = authorMatcher.group(2);
            if (author != null) {
                if (authors.length() > 0) authors.append(", ");
                authors.append(author.trim());
            }
        }
        if (authors.length() > 0) {
            codeFile.setAuthors(authors.toString());
        }
        
        // 提取文件描述（文件头注释）
        String description = extractFileDescription(header);
        if (description != null && !description.isEmpty()) {
            codeFile.setDescription(description);
        }
    }
    
    /**
     * 提取文件描述（从文件头注释中）
     */
    private String extractFileDescription(String content) {
        // 匹配C/C++多行注释
        Pattern descPattern = Pattern.compile("/\\*\\*(.*?)\\*/", Pattern.DOTALL);
        Matcher matcher = descPattern.matcher(content);
        
        if (matcher.find()) {
            String comment = matcher.group(1);
            // 清理注释格式
            comment = comment.replaceAll("(?m)^\\s*\\*\\s?", "")
                           .replaceAll("\\s+", " ")
                           .trim();
            
            // 限制长度
            if (comment.length() > 500) {
                comment = comment.substring(0, 500) + "...";
            }
            return comment;
        }
        
        return null;
    }
    
    /**
     * 计算文件内容的MD5
     */
    private String calculateMD5(String content) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hash = md.digest(content.getBytes(StandardCharsets.UTF_8));
            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }
    
    /**
     * 判断是否是支持的文件类型
     */
    private boolean isSupportedFile(Path file) {
        String fileName = file.getFileName().toString().toLowerCase();
        for (String ext : SUPPORTED_EXTENSIONS) {
            if (fileName.endsWith(ext)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 获取文件扩展名
     */
    private String getFileExtension(Path file) {
        String fileName = file.getFileName().toString();
        int lastDot = fileName.lastIndexOf('.');
        return lastDot > 0 ? fileName.substring(lastDot) : "";
    }
    
    /**
     * 判断是否应该跳过该目录
     */
    private boolean shouldSkipDirectory(String dirName) {
        // 跳过隐藏目录、构建目录等
        return dirName.startsWith(".") ||
               dirName.equals("build") ||
               dirName.equals("out") ||
               dirName.equals("node_modules") ||
               dirName.equals("__pycache__") ||
               dirName.equals("target") ||
               dirName.equals("bin") ||
               dirName.equals("obj");
    }
}

